package org.fujene.memoryblock.blockwise;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import org.fujene.constants.Constants;
import org.fujene.diskblock.DiskBlock;
import org.fujene.memoryblock.MemoryBlock;
import org.fujene.structure.InvertIndexData;
import org.fujene.structure.LookupPointer;
import org.fujene.toolbox.ByteConverter;

public class BlockwiseInvertIndexBlock extends MemoryBlock{
	private int opt_length = 0;

	public BlockwiseInvertIndexBlock(int bodySize, int ID, boolean isAllocate){
		super(bodySize, ID, Constants.MEMORY_TYPE_INVINDEX, isAllocate);
	}

	// 相対ポインタ対応
	public InvertIndexData getInvertIndex(int ptr){
		LookupPointer prevPtr, contentPtr;

		prevPtr = LookupPointer.fromBytesShort(getBody(ptr, RELPTR));
		if (prevPtr.equals(LookupPointer.EMPTY_RELATIVE))
			prevPtr = null;
		else prevPtr.block += this.getID();
		ptr += RELPTR;

		contentPtr = LookupPointer.fromBytesShort(getBody(ptr, RELPTR));
		if (contentPtr.equals(LookupPointer.EMPTY_RELATIVE))
			contentPtr = null;
		else contentPtr.block += this.getID();
		ptr += RELPTR;

		contentPtr.termfreq = ByteConverter.byteToInt(getBody(ptr, TERMFREQ));

		return new InvertIndexData(prevPtr, contentPtr, contentPtr.termfreq);
	}

	// 末尾に追加するのみ 相対ポインタ対応
	public LookupPointer setInvertIndex(LookupPointer prevPtr, LookupPointer docPtr, int termfreq){
		int ptr = this.bodySize - this.bodyVacancy - (2 * RELPTR) - TERMFREQ;

		opt_length++;

		if (prevPtr != null && !prevPtr.equals(LookupPointer.EMPTY)){
			prevPtr.block -= this.getID();
			setBody(prevPtr.toBytesShort(), ptr);
			prevPtr.block += this.getID();
		}else{
			setBody(LookupPointer.EMPTY_RELATIVE.toBytesShort(), ptr);
		}
		ptr += RELPTR;

		if (docPtr != null){
			docPtr.block -= this.getID();
			setBody(docPtr.toBytesShort(), ptr);
			docPtr.block += this.getID();
		}else{
			setBody(LookupPointer.EMPTY_RELATIVE.toBytesShort(), ptr);
		}
		ptr += RELPTR;

		setBody(ByteConverter.intToByte(termfreq, TERMFREQ), ptr);

		return new LookupPointer(this.getID(), ptr - RELPTR - RELPTR);
	}

	public int getLeft(){
		int returnNum = this.bodyVacancy / (2 * RELPTR + TERMFREQ);

		if (returnNum > 0) this.bodyVacancy -= (2 * RELPTR + TERMFREQ);

		return returnNum;
	}

	public static byte[] createByteArray(LookupPointer prevPtr, LookupPointer docPtr, int termfreq)
			throws IOException{
		ByteArrayOutputStream stream = new ByteArrayOutputStream();

		stream.write(prevPtr.toBytes());

		stream.write(docPtr.toBytes());

		stream.write(ByteConverter.intToByte(termfreq, TERMFREQ));

		return stream.toByteArray();
	}

	public byte[] getData() throws IOException{
		ByteArrayOutputStream stream = new ByteArrayOutputStream(this.bodySize + 12);

		stream.write(getOptionByteStream());
		stream.write(this.getBody(0, this.bodySize));

		return stream.toByteArray();
	}

	public void setData(byte[] array){
		opt_length = ByteConverter.byteToInt(array, 0, 4);

		setBody(array, 4, bodySize, 0);
	}

	@Override
	public int getOptionSize(){
		return 1;
	}

	@Override
	public byte[] getOptionByteStream(){
		return ByteConverter.intToByte(opt_length, 4);
	}

	@Override
	public int getOption(int num){
		switch(num){
		case 0:
			return opt_length;
		default:
			return 0;
		}
	}

	@Override
	public void setOption(int option, int value){
		if (option == 0) opt_length = value;
	}

	@Override
	public String getClassName(){
		return new String("InvertIndexBlock");
	}

	@Override
	public DiskBlock toDisk(int from, int to, String dir){
		return null;
	}
}
